package main

import (
	"basic-go/src/go-routine/util"
	"bufio"
	"fmt"
	"io"
	"math/rand"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"
)

// 启动一个writeDataFile协程，随机生成1000个数，放入文件中
// 当writeDataFile协程完成写1000个数据文件后，让sort协程从文件读取1000个数据，完成排序，重新写入到另一个文件

// 扩展：开启10个writeDataFile协程，每个协程随机生成1000个数据，放入10个文件，
// 当10个文件都生成后，让10个sort协程从10个文件读取1000个数据，完成排序后，重新写入10个结果文件。

var countDownLatch *util.CountDownLatch
var sortCountDownLatch *util.CountDownLatch

func writeDataToFile(fileNameChan chan<- string, index int) {
	fileName := fmt.Sprintf("d:/tmp/%d.txt", index)
	privateWriteDataToFile(fileName)
	fileNameChan <- fileName
	countDownLatch.CountDown()
}

func privateWriteDataToFile(filename string) {

	// 打开目标文件
	destFile, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)

	if err != nil {
		fmt.Printf("Open file error: %v\n", err)
		return
	}

	defer destFile.Close()

	// 创建流
	writer := bufio.NewWriter(destFile)
	// 如果不写，会丢失字节
	defer writer.Flush()

	rand.Seed(time.Now().UnixNano())

	for i := 1; i <= 1000; i++ {
		num := rand.Intn(100000)
		writer.WriteString(strconv.Itoa(num) + "\n")
	}
}

func dataHandle(srcFile string, destFile string) {
	arr := readDataFromFile(srcFile)
	sort.Ints(arr)
	rewriteDataToFile(destFile, arr)

	sortCountDownLatch.CountDown()
}

func readDataFromFile(filename string) []int {

	var result = make([]int, 0)

	// 打开文件
	file, err := os.Open(filename)

	if err != nil {
		fmt.Printf("Open file error: %v\n", err)
		return nil
	}

	defer file.Close()

	// 创建reader
	reader := bufio.NewReader(file)

	// 读取文件内容
	for {

		line, err := reader.ReadString('\n')

		if err == io.EOF {
			break
		}

		i, err := strconv.Atoi(strings.Trim(line, "\n"))
		if err == nil {
			result = append(result, i)
		}
	}

	return result
}

func rewriteDataToFile(filename string, arr []int) {

	// 打开目标文件
	destFile, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)

	if err != nil {
		fmt.Printf("Open file error: %v\n", err)
		return
	}

	defer destFile.Close()

	// 创建流
	writer := bufio.NewWriter(destFile)
	// 如果不写，会丢失字节
	defer writer.Flush()

	for _, num := range arr {
		writer.WriteString(strconv.Itoa(num) + "\n")
	}
}

func resolveFileNamePrefixSuffix(fileName string) (prefix string, suffix string) {
	index := strings.LastIndex(fileName, ".")
	if index == -1 {
		return fileName, ""
	}
	runes := []rune(fileName)
	return string(runes[:index]), string(runes[index:])
}

func main() {

	// 文件和协程数量
	count := 10

	// 开启10个writeDataFile协程写文件
	var fileNameChan = make(chan string, count)
	countDownLatch = util.NewCountDownLatch(count)

	for i := 1; i <= count; i++ {
		go writeDataToFile(fileNameChan, i)
	}

	// 异步关闭resultChan
	go func() {
		countDownLatch.Await()
		close(fileNameChan)
	}()

	// 读取文件并排序
	sortCountDownLatch = util.NewCountDownLatch(count)
	for fileName := range fileNameChan {
		prefix, suffix := resolveFileNamePrefixSuffix(fileName)
		go dataHandle(fileName, prefix+"_1"+suffix)
	}
	sortCountDownLatch.Await()
}
